package priv.abadstring.study.haoke.webapi.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import priv.abadstring.study.haoke.webapi.controller.GraphQLController;

import java.time.Duration;

/**
 * RedisCacheResponseBodyAdvice
 *
 * @author aBadString
 * @date 2021-07-29 19:59:31
 */
@ControllerAdvice
public class RedisCacheResponseBodyAdvice implements ResponseBodyAdvice {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean supports(MethodParameter returnType, Class aClass) {
        // GET 请求的 action 方法执行后, 调用 beforeBodyWrite
        if (returnType.hasMethodAnnotation(GetMapping.class)) {
            return true;
        }
        // POST 请求且是 GraphQLController 类中的 action 方法执行后, 调用 beforeBodyWrite
        if (returnType.hasMethodAnnotation(PostMapping.class) &&
                StringUtils.equals(
                        GraphQLController.class.getName(),
                        returnType.getExecutable().getDeclaringClass().getName())
                ) {
            return true;
        }
        return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass,
                                  ServerHttpRequest request, ServerHttpResponse serverHttpResponse) {
        try {
            String key = RedisCacheInterceptor.createRedisKey(
                    ((ServletServerHttpRequest) request).getServletRequest());
            String value;
            if (body instanceof String) {
                value = (String) body;
            } else {
                value = objectMapper.writeValueAsString(body);
            }
            this.redisTemplate.opsForValue().set(key, value, Duration.ofHours(1));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return body;
    }
}
